package com.yuyou.fn.settlement.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.CriteriaUtils;
import com.yuyou.fn.common.util.Principals;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.settlement.entity.AccountRecharge;
import com.yuyou.fn.settlement.entity.MainAccount;
import com.yuyou.fn.settlement.entity.PosPayRecord;
import com.yuyou.fn.settlement.mapper.AccountRechargeMapper;
import com.yuyou.fn.settlement.service.*;
import com.yuyou.fn.settlement.vo.AccountRechargeDetailVo;
import com.yuyou.fn.settlement.vo.AccountRechargeQueryVo;
import com.yuyou.fn.settlement.vo.PayWay;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 *
 * AccountRecharge 表数据服务层接口实现类
 *
 */
@Service
public class AccountRechargeServiceImpl extends SuperServiceImpl<AccountRechargeMapper, AccountRecharge,Long> implements IAccountRechargeService {

    @Resource
    private IMainAccountService mainAccountService;

    @Resource
    private INewPayRecordService newPayRecordService;

    @Resource
    private IPosPayService posPayService ;

    @Resource
    private ISettlementService settlementService;

    @Resource
    private Redisson redisson;

    @Override
    public AccountRecharge prepareAccountRecharge(Long  areaTeamId,Long accountRechargeId,Long mainAccountId, Long campusId, String campusName, BigDecimal amount , String remark, Long operatorId, String operatorName) {
        if (amount.doubleValue()<=0d){
            throw new BusException("金额必须大于0");
        }
        MainAccount mainAccount=mainAccountService.findById(mainAccountId);
        AccountRecharge accountRecharge=new AccountRecharge();
        accountRecharge.setAccountRechargeId(accountRechargeId);
        accountRecharge.setMainAccountId(mainAccount.getMainAccountId());
        accountRecharge.setMainAccountName(mainAccount.getName());
        accountRecharge.setBusTeamId(mainAccount.getBusTeamId());
        accountRecharge.setAreaTeamId(areaTeamId);
        accountRecharge.setCampusId(campusId);
        accountRecharge.setCampusName(campusName);
        accountRecharge.setAmount(amount);
        accountRecharge.setOperatorId(operatorId);
        accountRecharge.setOperatorName(operatorName);
        accountRecharge.setRemark(remark);
        accountRecharge.setState(0);
        accountRecharge.setCreateTime(TimeUtils.now());
        accountRecharge.setUpdateTime(TimeUtils.now());
        this.insertSelective(accountRecharge);
        return accountRecharge ;
    }

    @Transactional
    @Override
    public void finishAccountRecharge(Long accountRechargeId,Integer payWay ,String payInfoExt , Principals.Principal principal,BigDecimal amount) {
        RLock lock = redisson.getLock(String.format("accountRechargeId:%d", accountRechargeId ));
        if (lock.tryLock()) {
            try {
                if(principal == null ){
                    principal = Principals.getDefaultPrincipal() ;
                }

                AccountRecharge accountRecharge = findById(accountRechargeId);
                if (accountRecharge.getState()!=null && accountRecharge.getState()==2){
                    return;
                }
                accountRecharge.setAmount(amount);
                accountRecharge.setState(2);
                accountRecharge.setPayWay(payWay);
                accountRecharge.setPayTime(TimeUtils.now());
                accountRecharge.setUpdateTime(TimeUtils.now());
                accountRecharge.setOperatorId(principal.id);
                accountRecharge.setOperatorName(principal.name);
                this.updateSelectiveById(accountRecharge);
                newPayRecordService.savePayRecord( accountRechargeId,1,true,accountRecharge.getAmount()  ,accountRecharge.getCampusId() , Arrays.asList(new PayWay(payWay,amount,payInfoExt)),payInfoExt,principal  ) ;
                settlementService.increaseBalance(accountRecharge.getMainAccountId(),accountRecharge.getAmount(),accountRecharge.getRemark());
            }finally {
                lock.unlock();
            }
        }
           }

    @Override
    public void cancelAccountRecharge(Long accountRechargeId) {

        AccountRecharge accountRecharge = findById(accountRechargeId);

        if(accountRecharge.getState() != 0 &&  accountRecharge.getState() == 2 ){
            throw new BusException("不能取消");
        }

        if(accountRecharge.getPayWay() != null && accountRecharge.getPayWay() == 1 ){
            if( posPayService.isPayingForOrder(accountRechargeId)){
                throw new BusException("正在等待支付结果，暂时不能取消，5分钟重试");
            }
        }

        accountRecharge.setState(4);
        accountRecharge.setUpdateTime(TimeUtils.now());
        accountRecharge.setAccountRechargeId(accountRechargeId);
        this.updateSelectiveById(accountRecharge);
    }

    @Override
    public Long rechargeBalance(Long areaTeamId,Long mainAccountId, Long campusId, String campusName, BigDecimal amount, String remark) {
        Principals.Principal principal=Principals.get();
        if (principal==null){
            throw new BusException("请登录后操作");
        }
        Long accountRechargeId=IdWorker.getId();

        PosPayRecord posPayRecord = new PosPayRecord();
        posPayRecord.setRequestPayId(IdWorker.getId());
        posPayRecord.setAmount(amount.multiply(BigDecimal.valueOf(100)));
        posPayRecord.setBusOrderId(accountRechargeId);
        posPayRecord.setBusType(1);
        posPayRecord.setChargeCampusId(campusId);
        JSONObject extra = new JSONObject();
        extra.put("operator",principal);
        posPayRecord.setExtra(extra.toJSONString());
        posPayService.savePayRecord(posPayRecord);
        this.prepareAccountRecharge(areaTeamId,accountRechargeId,mainAccountId,campusId,campusName,amount,remark,principal.id,principal.name);
        return posPayRecord.getRequestPayId();
    }



    @Override
    public Page<AccountRecharge> findPageByQuery(AccountRechargeQueryVo accountRechargeQueryVo, int pageNo, int pageSize) {
        Example<AccountRecharge> example=AccountRecharge.createExample();
        Example.Criteria criteria=example.createCriteria();
        CriteriaUtils.fillCondition(criteria,accountRechargeQueryVo);

        return this.findPageByExample(example,pageNo,pageSize);
    }



    public static SXSSFWorkbook rechargeBalance2Excel(List<AccountRechargeDetailVo> accountRechargeDetailVoList) {

        SXSSFWorkbook excel = new SXSSFWorkbook();
        SXSSFSheet sheet = excel.createSheet("学生充值管理");
        SXSSFRow firstRow = sheet.createRow(0);
        String[] titles = new String[]{ "学生姓名", "学号", "手机号","充值金额", "操作人", "受理校区","订单状态","订单生成时间","支付时间","充值方式"};
        for (int i = 0; i < titles.length; i++) {
            firstRow.createCell(i).setCellValue(titles[i]);
        }
        int rowNum = 1;
        Map<Integer,String> payWayMap=new HashMap<>();
        payWayMap.put(1,"pos充值");
        payWayMap.put(5,"线上充值");
        payWayMap.put(7,"TMS充值");
        if (accountRechargeDetailVoList!=null){
            for (AccountRechargeDetailVo accountRechargeDetailVo : accountRechargeDetailVoList) {
                int cellNum = 0;

                SXSSFRow row = sheet.createRow(rowNum++);

                SXSSFCell cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(accountRechargeDetailVo.getMainAccountName()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(accountRechargeDetailVo.getStudentNo()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(accountRechargeDetailVo.getPhoneNo()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(accountRechargeDetailVo.getAmount().toString());

                cell = row.createCell(cellNum++);
                cell.setCellValue(accountRechargeDetailVo.getOperatorName());

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(accountRechargeDetailVo.getCampusName()));

                /** 0 未支付， 2已支付 ，4 已取消 */
                cell = row.createCell(cellNum++);
                cell.setCellValue(accountRechargeDetailVo.getState()!=null?accountRechargeDetailVo.getState()==0?"未支付":accountRechargeDetailVo.getState()==2?"已支付":"已取消":"");


                cell = row.createCell(cellNum++);
                cell.setCellValue(accountRechargeDetailVo.getCreateTime()==null?"": Utils.formatDate(accountRechargeDetailVo.getCreateTime(),"yyyy-MM-dd HH:mm:ss"));

                cell = row.createCell(cellNum++);
                cell.setCellValue(accountRechargeDetailVo.getPayTime()==null?"": Utils.formatDate(accountRechargeDetailVo.getPayTime(),"yyyy-MM-dd HH:mm:ss"));

                /** 支付方式：0-现金；1-刷卡；2-转账；3-账户 4-在线支付 5-其他,7-tms账户迁入 */
                cell = row.createCell(cellNum++);
                cell.setCellValue(payWayMap.get(accountRechargeDetailVo.getPayWay())==null?"":payWayMap.get(accountRechargeDetailVo.getPayWay()));


            }
        }
        return excel;
    }


    @Override
    public List<AccountRecharge> findAccountRecharge(Integer state, Date date) {
        Example<AccountRecharge> example= AccountRecharge.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andEqualTo("state",state);
        criteria.andGreaterThan("createTime",date);
        List<AccountRecharge> accountRechargeList =this.findListByExample(example);
        return accountRechargeList;
    }
}